import React, { useEffect, useRef, useState } from "react";
import lessModule from "./index.module.less"
import { Button, Input, InputNumber, Select, Upload, UploadFile } from "antd";
import { $labelDictInterface } from "../../../../common/type";
import TextArea from "antd/es/input/TextArea";
import { $Http } from "../../../../network";


// 主页_模型微调页面
const HomePage_FineTuningPage = () => {
  // 错误字典
  const [errDict, setErrDict] = useState<{ [key: string]: boolean }>({});
  // 图片文件夹路径
  let [imageList, setImageList] = useState<Array<any>>([]);
  // 图片文本
  let [imageTxt, setImageTxt] = useState<string>("");
  // 标签
  const [tag, setTag] = useState<string>("");
  // 基础模型列表
  const [baseModelList, setBaseModelList] = useState<Array<$labelDictInterface>>([]);
  // 基础模型
  const [baseModel, setBaseModel] = useState<string | null>(null);
  // 新模型名称
  const [newModelName, setNewModalName] = useState<string>("");
  // 学习率
  const [lr, setLr] = useState<number>(0.0001);
  // 训练周期
  const [epochs, setEpochs] = useState<number>(20);
  // 任务ID
  const taskID = useRef<number>(0)
  // log状态
  let [logStatus, setLogStatus] = useState<string>("")
  // log定时器
  const logInterval = useRef<NodeJS.Timeout | null>(null);
  // 日志
  let [log, setLog] = useState<string>("");

  /**
   * @brief 点击上传文件夹
   * @param 
   * @return 
   * @note 
   * @warning 
   */
  const click_uploadFolder = () => {
    imageList = []
    errDict.imageTxt = false
    setImageList([...imageList])
    setImageTxt("");
    setErrDict({ ...errDict })
  }
  /**
   * @brief 上传文件夹之前
   * @param
   * @return 
   * @note 
   * @warning 是否自动上传
   */
  const beforeUpload_folder = (file: File, fileList: Array<File>) => {
    imageList = fileList.filter((item: File) => item.type === "image/jpeg" || item.type === "image/png")
    errDict.imageTxt = !imageList.length
    setImageList([...imageList]);
    setErrDict({ ...errDict });
    setImageTxt(`本次上次共有 ${imageList.length} 张图片`);
    return false
  }



  /**
   * @brief 更改标签
   * @param event: any 上传的文件对象
   * @return 
   * @note 
   * @warning 
   */
  const change_tag = (event: any) => {
    errDict.tag = !event.target.value
    setTag(event.target.value)
    setErrDict({ ...errDict });
  }

  /**
   * @brief 加载.txt文件内容
   * @param event: any 上传的文件对象
   * @return 
   * @note 
   * @warning 
   */
  const beforeUpload_txt = (event: File) => {
    const reader = new FileReader();
    reader.onload = (event: any) => {
      setTag(event.target.result)
      errDict.tag = !event.target.result
      setErrDict({ ...errDict });
    };
    reader.readAsText(event);
    return false; // 阻止自动上传
  }
  /**
   * @brief 监听基础模型
   * @param value: string 选中的基础模型名称
   * @return 
   * @note 
   * @warning 
   */
  const change_baseModel = (value: string) => {
    errDict.baseModel = !value
    setBaseModel(value);
    setErrDict({ ...errDict });

  }
  /**
   * @brief 监听新模型名称
   * @param event: any 输入事件对象
   * @return 
   * @note 
   * @warning 
   */
  const change_newModelName = (event: any) => {
    errDict.newModelName = !event.target.value
    setNewModalName(event.target.value)
    setErrDict({ ...errDict });
  }
  /**
   * @brief 监听学习率
   * @param event: any 输入事件对象
   * @return 
   * @note 
   * @warning 
   */
  const change_lr = (event: any) => {
    errDict.lr = event === null
    setLr(event)
    setErrDict({ ...errDict });
  }
  /**
   * @brief 监听训练周期
   * @param event: any 输入事件对象
   * @return 
   * @note 
   * @warning 
   */
  const change_epochs = (event: any) => {
    errDict.epochs = event === null
    setEpochs(event)
    setErrDict({ ...errDict });
  }


  /**
   * @brief 点击开始微调按钮
   * @param 
   * @return 
   * @note 
   * @warning 
   */
  const click_fineTuning = () => {
    errDict.imageTxt = !imageTxt
    errDict.tag = !tag
    errDict.baseModel = !baseModel
    errDict.newModelName = !newModelName
    errDict.lr = lr === null
    errDict.epochs = epochs === null
    setErrDict({ ...errDict });
    !Object.values(errDict).filter((item: boolean) => item).length && http_finetuneStart()
  }

  /**
   * @brief 获取推理模型
   * @param 
   * @return 
   * @note 
   * @warning 
   */
  const http_inference = () => {
    $Http("inference", {}).then((res: object) => {
      setBaseModelList([...res["model_list"]])
      setBaseModel(res["model_list"][0].label ?? "")
    })
  }
  /**
   * @brief 开始微调
   * @param 
   * @return 
   * @note 
   * @warning 
   */
  const http_finetuneStart = () => {
    const formData = new FormData();
    log = ""
    setLog(log)
    formData.append('labels', tag);
    formData.append('base_model', baseModel ?? "");
    formData.append('new_model_name', newModelName);
    formData.append('lr', lr.toString());
    formData.append('epochs', epochs.toString());
    // 将File对象添加到FormData中
    imageList.forEach((item: File) => {
      formData.append('files', item);
    })

    $Http("finetuneStart", formData, "post", "file").then((res: object) => {
      taskID.current = res["task_id"]
      http_finetuneStatus()
      logInterval.current = setInterval(() => {
        http_finetuneStatus()
      }, 1000);
    })
  }
  /**
 * @brief 微调中
 * @param 
 * @return 
 * @note 
 * @warning 
 */
  const http_finetuneStatus = () => {
    $Http("finetuneStatus", { taskID: taskID.current }).then((res: object) => {
      logStatus = res["status"]
      if (logStatus === "completed") {
        logInterval.current && clearInterval(logInterval.current)
        http_inference()
      }
      log += res["logs"] && "\n" + res["logs"]
      setLogStatus(logStatus)
      setLog(log)
    })
  }
  useEffect(() => {
    http_inference()
    return () => {
      logInterval.current && clearInterval(logInterval.current)
    }
  }, [])

  return (
    <div className={lessModule["homePageReasoningPage"]} >
      <div className={`${lessModule["homePageReasoningPage-card"]} ${lessModule["homePageReasoningPage-setting"]}`} >
        {/* <div className={lessModule["homePageReasoningPage-card__title"]}>微调设置（默认参数: {epochs}个周期,学习率{lr.toExponential()}）</div> */}
        <div className={lessModule["homePageReasoningPage-card__panel"]} >
          <span>1.选择数据</span>
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>图片文件夹：</span>
            <Input placeholder="请浏览..." value={imageTxt} disabled />
            <Upload fileList={imageList} directory beforeUpload={beforeUpload_folder}>
              <Button type="primary" onClick={click_uploadFolder}>浏览...</Button>
            </Upload>
          </div>
          {
            errDict.imageTxt && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请浏览...</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>标签（加载.txt或直接输入）：</span>
            <Input placeholder="请加载.txt或直接输入" value={tag} onChange={change_tag} />
            <Upload accept=".txt" beforeUpload={beforeUpload_txt}>
              <Button type="primary">加载.txt</Button>
            </Upload>
          </div>
          {
            errDict.tag && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请加载.txt或直接输入</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}></span>
            <div className={lessModule["setting-row__describe"]}>说明：图片需按'001.jpg / 001.png"等排序。标签格式为[0,1,5,…]</div>
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          <div className={lessModule["homePageReasoningPage-setting__divider"]} />
          <span>2.选择模型</span>
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>基础模型(.onnx)：</span>
            <Select placeholder="请选择" value={baseModel} options={baseModelList} fieldNames={{ value: "label" }} onChange={change_baseModel} />
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          {
            errDict.baseModel && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请选择</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}></span>
            <div className={lessModule["setting-row__describe"]}>注意：只有同时存在同名,pt文件的模型才能被微调。</div>
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>新模型名称：</span>
            <Input placeholder="请输入" value={newModelName} onChange={change_newModelName} />
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          {
            errDict.newModelName && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请输入</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>学习率：</span>
            <InputNumber placeholder="请输入" value={lr} min={0} onChange={change_lr} />
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          {
            errDict.lr && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请输入</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__row"]}>
            <span className={lessModule["setting-row__label"]}>训练周期（Epochs）：</span>
            <InputNumber placeholder="请输入" value={epochs} min={1} precision={0} onChange={change_epochs} />
            <div className={lessModule["setting-row__emptyBtn"]}></div>
          </div>
          {
            errDict.epochs && <div className={`${lessModule["homePageReasoningPage-setting__row"]} ${lessModule["homePageReasoningPage-setting__err"]}`}>
              <span className={lessModule["setting-row__label"]}></span>
              <div>请输入</div>
              <div className={lessModule["setting-row__emptyBtn"]}></div>
            </div>
          }
          <div className={lessModule["homePageReasoningPage-setting__submit"]}>
            <Button type="primary" disabled={logStatus === "running"} onClick={click_fineTuning}>开始微调</Button>
          </div>
        </div>
      </div>
      <div className={`${lessModule["homePageReasoningPage-card"]} ${lessModule["homePageReasoningPage-log"]}`} style={{ height: `calc(100% - 518px - ${Object.values(errDict).filter((item: boolean) => item).length * 24}px)` }}>
        <div className={`${lessModule["homePageReasoningPage-card__title"]} ${lessModule["homePageReasoningPage-log__title"]}`}>训练日志</div>
        <div className={`${lessModule["homePageReasoningPage-card__panel"]} ${lessModule["homePageReasoningPage-log__panel"]}`} >
          <div className={lessModule["log-panel__container"]}>  {log ? log.split('\n').map((item, idx) => (
            <React.Fragment key={`log_item_${idx}`}>
              {item}
              {idx > 0 && <br />}
            </React.Fragment>
          )) : ""} </div>
        </div>

      </div>
    </div>
  )
}

export default HomePage_FineTuningPage